package com.cs.netty.simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.CharsetUtil;

import java.util.concurrent.TimeUnit;

/**
 * @ClassName: NettyServerHandler
 * @Description: 说明
 * 1. 自定义一个Handler 需要继承netty 规定好的某个HandlerAdapter(规范)
 * 2. 这时我们自定义一个Handler，才能称为一个Handler
 *
 * @Author: kevin
 * @Date: 2020/8/11 10:28
 * @Version: 1.0
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 读取数据事件(这里我们可以读取客户端发送的消息)
     * @param ctx   上下文对象，含有管道pipeline，通道channel，地址
     * @param msg   就是客户端发送的数据(被封装为一个对象) 默认是Object
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        // 比如这里有一个非常耗时时间的业务 -> 异步执行 -> 提交该 channel 对应的 NIOEventLoop 的 taskQueue 中

        // 解决方案1 用户线程自定义的普通任务

        ctx.channel().eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端~ 哈哈2", CharsetUtil.UTF_8));
                } catch (InterruptedException e) {
                    System.out.println("发生异常" + e.getMessage());
                }
            }
        });

        ctx.channel().eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5 * 1000);
                    // 30秒
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端~ 哈哈3", CharsetUtil.UTF_8));
                } catch (InterruptedException e) {
                    System.out.println("发生异常" + e.getMessage());
                }
            }
        });

        // 解决方案2. 用户自定义定时任务 -> 该任务提交到 scheduleTaskQueue中
        ctx.channel().eventLoop().schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5 * 1000);
                    // 30秒
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端~ 哈哈4", CharsetUtil.UTF_8));
                } catch (InterruptedException e) {
                    System.out.println("发生异常" + e.getMessage());
                }
            }
        }, 5, TimeUnit.SECONDS);


        System.out.println("go on ...");


        System.out.println("服务器读取线程 " + Thread.currentThread().getName() + " channel =" + ctx.channel());
//        System.out.println("Server ctx =" + ctx);
//        System.out.println("看看channel 和 pipeline 的关系");
//        Channel channel = ctx.channel();
//        ChannelPipeline pipeline = ctx.pipeline(); // 本事是一个双向链表
//        // 将msg转为一个 ByteBuf
//        // ByteBuf 是netty 提供的， 不是 NIO 的 ByteBuff
//        ByteBuf buf = (ByteBuf) msg;
//        System.out.println("客户端发送消息是:" + buf.toString(CharsetUtil.UTF_8));
//        System.out.println("客户端地址:" + channel.remoteAddress());
    }

    /**
     * 数据读取完毕
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // writeAndFlush 是 write + Flush
        // 将数据写入到缓存，并刷新
        // 一般将，我们对这个发送的数据进行编码
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端~ 哈哈1", CharsetUtil.UTF_8));
    }

    /**
     * 处理异常，一般是需要关闭通道
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//        ctx.channel().close();
        ctx.close();
    }
}
